using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Globalization;
using System.IO;
using SDMX_Message = SDMX_ML.Framework.Message;
using SDMX_Generic = SDMX_ML.Framework.Generic;
using SDMX_ML.Framework.Interfaces;
using SDMX_Common = SDMX_ML.Framework.Common;


namespace SDMX_ML.Framework.Messages
{
    /// <summary>
    /// Genericdata message.
    /// </summary>
    public class GenericData : IMessage
    {
        #region Fields

        private XDocument _xmldoc;
        private XElement _xml;
        private XNamespace _nsQueryMessage;
        private XNamespace _nsGeneric;
        private XNamespace _default;
        private XNamespace _nsMessage;

        private SDMX_Generic.DataSetType _dataset = null;
        private SDMX_Message.HeaderType _header = null;

        #endregion

        #region Constructors

        /// <summary>
        /// Creates objects from the xml file in the parameter
        /// </summary>
        /// <param name="xml">A SDMX_ML QueryMessage with the DataWhere element in a string</param>
        public GenericData(string xml)
        {
            _xml = XElement.Parse(xml);
            //_dataset = new SDMX_Generic.DataSet();

            setNameSpace();

            XElement header = _xml.Element(_nsMessage + "Header");

            if (header != null)
            {
                _header = new SDMX_Message.HeaderType(header);
            }

            setDataSet();
        }

        /// <summary>
        /// Creates a SDMX_ML GenericDataMessage that can write a xml file
        /// </summary>
        public GenericData()
        {
 
        }

        #endregion

        #region Create Objects from XML

        private void setNameSpace()
        {
            _nsQueryMessage = _xml.Name.Namespace;
            _nsGeneric = _xml.GetNamespaceOfPrefix("generic");
            _default = _xml.GetDefaultNamespace();

            //Finding the prefix used for the message namespace
            string prefixMessage = _xml.GetPrefixOfNamespace(Namespaces.GetNS("message"));

            if (prefixMessage != null)
            {
                //create the common namespace used in the xml structure file
                _nsMessage = _xml.GetNamespaceOfPrefix(prefixMessage);
            }
            else
            {
                _nsMessage = _xml.GetDefaultNamespace();
            }
        }

 
        private void setDataSet()
        {
            XElement ds = null;

            if(_xml.Element(_default + "DataSet") != null)
            {
                ds = _xml.Element(_default + "DataSet");
            }
            else if(_xml.Element(_nsGeneric + "DataSet") != null) //If DataSet belongs to a MessageGroup
            {
                ds = _xml.Element(_nsGeneric + "DataSet");
            }

            if(ds != null)
            {
                if (ds.Element(_nsGeneric + "KeyFamilyRef") != null)
                {
                    _dataset  = new SDMX_Generic.DataSetType(ObjectBuilder.GetIDType(ds.Element(_nsGeneric + "KeyFamilyRef").Value));
                }
                else
                {
                    throw new Exception("Element keyFamilyRef is missing in DataSet element.");
                }

                if (ds.Attribute("keyFamilyURI") != null)
                {
                    if (!String.IsNullOrEmpty(ds.Attribute("keyFamilyURI").Value))
                    {
                        _dataset.KeyFamilyURI = ds.Attribute("keyFamilyURI").Value;
                    }
                }

                if (ds.Attribute("datasetID") != null)
                {
                    if (!String.IsNullOrEmpty(ds.Attribute("datasetID").Value))
                    {
                        SDMX_Common.IDType idType = new SDMX_Common.IDType();
                        idType.Value = ds.Attribute("datasetID").Value;
                        _dataset.DataSetID = idType;
                    }
                }

                if (ds.Attribute("dataProviderSchemeAgencyId") != null)
                {
                    if (!String.IsNullOrEmpty(ds.Attribute("dataProviderSchemeAgencyId").Value))
                    {
                        SDMX_Common.IDType idType = new SDMX_Common.IDType();
                        idType.Value = ds.Attribute("dataProviderSchemeAgencyId").Value;
                        _dataset.DataproviderSchemeAgencyId = idType;
                    }
                }

                if (ds.Attribute("dataProviderSchemeId") != null)
                {
                    if (!String.IsNullOrEmpty(ds.Attribute("dataProviderSchemeId").Value))
                    {
                        SDMX_Common.IDType idType = new SDMX_Common.IDType();
                        idType.Value = ds.Attribute("dataProviderSchemeId").Value;
                        _dataset.DataProviderSchemeId = idType;
                    }
                }

                if (ds.Attribute("dataProviderID") != null)
                {
                    if (!String.IsNullOrEmpty(ds.Attribute("dataProviderID").Value))
                    {
                        SDMX_Common.IDType idType = new SDMX_Common.IDType();
                        idType.Value = ds.Attribute("dataProviderID").Value;
                        _dataset.DataProviderId = idType;
                    }
                }

                if (ds.Attribute("dataflowAgencyID") != null)
                {
                    if (!String.IsNullOrEmpty(ds.Attribute("dataflowAgencyID").Value))
                    {
                        SDMX_Common.IDType idType = new SDMX_Common.IDType();
                        idType.Value = ds.Attribute("dataflowAgencyID").Value;
                        _dataset.DataflowAgencyID = idType;
                    }
                }

                if (ds.Attribute("dataflowID") != null)
                {
                    if (!String.IsNullOrEmpty(ds.Attribute("dataflowID").Value))
                    {
                        SDMX_Common.IDType idType = new SDMX_Common.IDType();
                        idType.Value = ds.Attribute("dataflowID").Value;
                        _dataset.DataflowID = idType;
                    }
                }

                if (ds.Attribute("action") != null)
                {
                    if (!String.IsNullOrEmpty(ds.Attribute("action").Value))
                    {
                        _dataset.Action = SDMX_Common.EnumerationConvert.EnumDataSetActionFromString(ds.Attribute("action").Value);
                    }
                }

                if (ds.Attribute("reportingBeginDate") != null)
                {
                    if (!String.IsNullOrEmpty(ds.Attribute("reportingBeginDate").Value))
                    {
                        SDMX_Common.TimePeriodType timePeriod = new SDMX_Common.TimePeriodType();
                        timePeriod.TimePeriod = ds.Attribute("reportingBeginDate").Value;
                        _dataset.ReportingBeginDate = timePeriod;
                    }
                }

                if (ds.Attribute("reportingEndDate") != null)
                {
                    if (!String.IsNullOrEmpty(ds.Attribute("reportingEndDate").Value))
                    {
                        SDMX_Common.TimePeriodType timePeriod = new SDMX_Common.TimePeriodType();
                        timePeriod.TimePeriod = ds.Attribute("reportingEndDate").Value;
                        _dataset.ReportingEndDate = timePeriod;
                    }
                }

                if (ds.Attribute("validFromDate") != null)
                {
                    if (!String.IsNullOrEmpty(ds.Attribute("validFromDate").Value))
                    {
                        SDMX_Common.TimePeriodType timePeriod = new SDMX_Common.TimePeriodType();
                        timePeriod.TimePeriod = ds.Attribute("validFromDate").Value;
                        _dataset.ValidFromDate = timePeriod;
                    }
                }

                if (ds.Attribute("validToDate") != null)
                {
                    if (!String.IsNullOrEmpty(ds.Attribute("validToDate").Value))
                    {
                        SDMX_Common.TimePeriodType timePeriod = new SDMX_Common.TimePeriodType();
                        timePeriod.TimePeriod = ds.Attribute("validToDate").Value;
                        _dataset.ValidToDate = timePeriod;
                    }
                }

                if (ds.Attribute("publicationYear") != null)
                {
                    if (!String.IsNullOrEmpty(ds.Attribute("publicationYear").Value))
                    {
                        _dataset.PublicationYear = ds.Attribute("publicationYear").Value;
                    }
                }

                if (ds.Attribute("publicationPeriod") != null)
                {
                    if (!String.IsNullOrEmpty(ds.Attribute("publicationPeriod").Value))
                    {
                        SDMX_Common.TimePeriodType timePeriod = new SDMX_Common.TimePeriodType();
                        timePeriod.TimePeriod = ds.Attribute("publicationPeriod").Value;
                        _dataset.PublicationPeriod = timePeriod;
                    }
                }

                

                if(ds.Element(_nsGeneric + "Attributes") != null)
                {
                    foreach (XElement e in ds.Elements(_nsGeneric + "Attributes"))
                    {
                        _dataset.Attributes.Add(setValueType(e));
                    }
                }

                //Choice
                if(ds.Element(_nsGeneric + "Group") != null)
                {
                    foreach (XElement group in ds.Elements(_nsGeneric + "Group"))
                    {
                        _dataset.Group.Add(setGroup(ds.Element(_nsGeneric + "Group")));
                    }
                }
                else if (ds.Element(_nsGeneric + "Series") != null)
                {
                    _dataset.Series.Add(setSeries(ds.Element(_nsGeneric + "Series")));
                }

                if(ds.Element(_nsGeneric + "Annotations") != null)
                {
                    _dataset.Annotations = ObjectBuilder.GetAnnotationsType(ds.Element(_nsGeneric + "Annotations"));
                }
            }
        }

        private SDMX_Generic.GroupType setGroup(XElement element)
        {
            SDMX_Generic.GroupType group = null;

            if(element != null)
            {
                if (element.Attribute("type") != null)
                {
                    if (element.Attribute("type").Value != null)
                    {
                        group = new SDMX_Generic.GroupType(element.Attribute("type").Value);
                    }
                    else
                    {
                        throw new Exception("Value is missing in attribute type in GroupType.");
                    }
                }
                else
                {
                    throw new Exception("Type is missing in GroupType.");
                }

                if(element.Element(_nsGeneric + "GroupKey") != null)
                {
                    foreach (XElement e in element.Elements(_nsGeneric + "GroupKey"))
                    {
                        foreach (XElement val in e.Elements(_nsGeneric + "Value"))
                        {
                            group.Groupkey.Add(setValueType(val));
                        }
                    }
                }

                if(element.Element(_nsGeneric + "Attributes") != null)
                {
                    foreach (XElement e in element.Elements(_nsGeneric + "Attributes"))
                    {
                        foreach (XElement val in e.Elements(_nsGeneric + "Value"))
                        {
                            group.Attributes.Add(setValueType(val));
                        }
                    }
                }

                if(element.Element(_nsGeneric + "Series") != null)
                {
                    foreach (XElement series in element.Elements(_nsGeneric + "Series"))
                    {
                        group.Series.Add(setSeries(series));
                    }
                }

                if(element.Element(_nsGeneric + "Annotations") != null)
                {
                    group.Annotations = ObjectBuilder.GetAnnotationsType(element.Element(_nsGeneric + "Annotations"));
                }
            }

            return group;
        }

        private SDMX_Generic.ValueType setValueType(XElement attribute)
        {
            SDMX_Generic.ValueType value = null;
            SDMX_Common.IDType concept = null;
            string attributeValue = string.Empty;

            if(attribute != null)
            {

                if (attribute.Attribute("concept") != null)
                {
                    if (attribute.Attribute("concept").Value != null)
                    {
                        SDMX_Common.IDType id = new SDMX_Common.IDType();
                        id.Value = attribute.Attribute("concept").Value;
                        concept = id;
                    }
                    else
                    {
                        throw new Exception("Value in attribute concept is missing in element Value");
                    }
                }
                else
                {
                    throw new Exception("Attribute concept is missing in element Value");
                }

                if (attribute.Attribute("value") != null)
                {
                    if (attribute.Attribute("value").Value != null)
                    {
                        attributeValue = attribute.Attribute("value").Value;
                    }
                    else
                    {
                        throw new Exception("Value in attribute value is missing in element Value");
                    }
                }
                else
                {
                    throw new Exception("Attribute value is missing in element Value");
                }

                value = new SDMX_Generic.ValueType(attributeValue, concept);

                if(attribute.Attribute("startTime") != null)
                {
                    if (attribute.Attribute("startTime").Value != null)
                    {
                        value.StartTime = attribute.Attribute("startTime").Value;
                    }
                }
            }

            return value;
            
        }

        private SDMX_Generic.SeriesType setSeries(XElement element)
        {
            SDMX_Generic.SeriesType series = new SDMX_Generic.SeriesType();

            if(element.Element(_nsGeneric + "SeriesKey") != null)
            {
                XElement serieskey = element.Element(_nsGeneric + "SeriesKey");

                foreach (XElement sk in serieskey.Elements(_nsGeneric + "Value"))
                {
                    series.Serieskey.Add(setValueType(sk));
                }
            }

            if(element.Element(_nsGeneric + "Attributes") != null)
            {
                XElement attributes = element.Element(_nsGeneric + "Attributes");

                foreach (XElement at in attributes.Elements(_nsGeneric + "Value"))
                {
                    series.Attributes.Add(setValueType(at));
                }
            }

            if (element.Element(_nsGeneric + "Obs") != null)
            {
                foreach (XElement obs in element.Elements(_nsGeneric + "Obs"))
                {
                    series.Obs.Add(setObs(obs));
                }
            }

            if(element.Element(_nsGeneric + "Annotations") != null)
            {
                series.Annotations = ObjectBuilder.GetAnnotationsType(element.Element(_nsGeneric + "Annotations"));
            }

            return series;
        }

        private SDMX_Generic.ObsType setObs(XElement element)
        {
            SDMX_Generic.ObsType obs = null;

            if (element.Element(_nsGeneric + "Time") != null)
            {
                if (!String.IsNullOrEmpty(element.Element(_nsGeneric + "Time").Value))
                {
                    obs = new SDMX_Generic.ObsType(element.Element(_nsGeneric + "Time").Value);
                }
                else
                {
                    throw new Exception("Value in time in ObsType is required.");
                }
            }
            else
            {
                throw new Exception("Time is required in ObsType.");
            }

            if(element.Element(_nsGeneric + "ObsValue") != null)
            {
                XElement obsvalue = element.Element(_nsGeneric + "ObsValue");

                SDMX_Generic.ObsValueType ovalue = null;
            
                if(obsvalue.Attribute("value") != null)
                {
                     if (obsvalue.Attribute("value").Value != null)
                    {
                        double val = Convert.ToDouble(obsvalue.Attribute("value").Value, CultureInfo.InvariantCulture);
                        ovalue = new SDMX_Generic.ObsValueType(val);
                    }
                }

                if(obsvalue.Attribute("startTime") != null)
                {
                    if (obsvalue.Attribute("startTime").Value != null)
                    {
                        ovalue.StartTime = obsvalue.Attribute("startTime").Value;
                    }
                }
                
                obs.ObsValue = ovalue;
            }

            if(element.Element(_nsGeneric + "Attributes") != null)
            {
                XElement attributes = element.Element(_nsGeneric + "Attributes");

                foreach (XElement at in attributes.Elements(_nsGeneric + "Value"))
                {
                    obs.Attributes.Add(setValueType(at));
                }
            }

            if(element.Element(_nsGeneric + "Annotations") != null)
            {
                obs.Annotations = ObjectBuilder.GetAnnotationsType(element.Element(_nsGeneric + "Annotations"));
            }

            return obs;
        }

        

        #endregion

        #region WriteXmlFile (From Objects to Xml) 

        /// <summary>
        /// Writing the SDMX_ML file
        /// </summary>
        /// <returns>A string containing the xml file in SDMX_ML format</returns>
        public string ToXml()
        {
            try
            {
                XElement x = GetXml();
                
                return _xmldoc.ToString();
            }
            catch(Exception ex)
            {
                Console.WriteLine(ex.Message);
                throw new Exception(ex.Message);
            }
        }

        /// <summary>
        /// Get message as XElement.
        /// </summary>
        /// <returns>XElement.</returns>
        public XElement GetXml()
        {
            _xmldoc = new XDocument(
                new XDeclaration("1.0", "UTF-8", "yes"));
            
                                   
            XElement genericdata = new XElement(Namespaces.GetNS("message") + "GenericData",
                new XAttribute(XNamespace.Xmlns + "generic", Namespaces.GetNS("generic")),
                new XAttribute(XNamespace.Xmlns + "common", Namespaces.GetNS("common")),
                new XAttribute(XNamespace.Xmlns + "compact", Namespaces.GetNS("compact")),
                new XAttribute(XNamespace.Xmlns + "cross", Namespaces.GetNS("cross")),
                new XAttribute(XNamespace.Xmlns + "query", Namespaces.GetNS("query")),
                new XAttribute(XNamespace.Xmlns + "structure", Namespaces.GetNS("structure")),
                new XAttribute(XNamespace.Xmlns + "utility", Namespaces.GetNS("utility")),
                new XAttribute(XNamespace.Xmlns + "xsi",Namespaces.GetXSI()),
                new XAttribute(Namespaces.GetXSI() + "schemaLocation", Namespaces.GetLocation())//Namespaces.GetNS("message") + "SDMXMessage.xsd")
                );
           
            if(_header != null)
            {
                genericdata.Add(_header.GetXml());
            }

            if (_dataset.Group != null)
            {
                genericdata.Add(getDataset(_dataset));
            }

            _xmldoc.Add(genericdata);
            
            return genericdata;
        }

        private XElement getDataset(SDMX_Generic.DataSetType ds)
        {
            XElement dataset = new XElement(Namespaces.GetNS("message") + "DataSet");

            if (!String.IsNullOrEmpty(ds.KeyFamilyURI))
            {
                dataset.Add(new XAttribute("keyFamilyURI", ds.KeyFamilyURI));
            }

            if (ds.DataSetID != null)
            {
                if (!String.IsNullOrEmpty(ds.DataSetID.Value))
                {
                    dataset.Add(new XAttribute("datasetID", ds.DataSetID.Value));
                }
            }

            if (ds.DataproviderSchemeAgencyId != null)
            {
                if (!String.IsNullOrEmpty(ds.DataproviderSchemeAgencyId.Value))
                {
                    dataset.Add(new XAttribute("dataProviderSchemeAgencyId", ds.DataproviderSchemeAgencyId.Value));
                }
            }

            if (ds.DataProviderSchemeId != null)
            {
                if (!String.IsNullOrEmpty(ds.DataProviderSchemeId.Value))
                {
                    dataset.Add(new XAttribute("dataProviderSchemeId", ds.DataProviderSchemeId.Value));
                }
            }

            if (ds.DataProviderId != null)
            {
                if (!String.IsNullOrEmpty(ds.DataProviderId.Value))
                {
                    dataset.Add(new XAttribute("dataProviderID", ds.DataProviderId.Value));
                }
            }

            if (ds.DataflowAgencyID != null)
            {
                if (!String.IsNullOrEmpty(ds.DataflowAgencyID.Value))
                {
                    dataset.Add(new XAttribute("dataflowAgencyID", ds.DataflowAgencyID.Value));
                }
            }

            if (ds.DataflowID != null)
            {
                if (!String.IsNullOrEmpty(ds.DataflowID.Value))
                {
                    dataset.Add(new XAttribute("dataflowID", ds.DataflowID.Value));
                }
            }

            if (ds.Action != null)
            {
                dataset.Add(new XAttribute("action", ds.Action.ToString()));
            }

            if (ds.ReportingBeginDate != null)
            {
                if (!String.IsNullOrEmpty(ds.ReportingBeginDate.TimePeriod))
                {
                    dataset.Add(new XAttribute("reportingBeginDate", ds.ReportingBeginDate.TimePeriod));
                }
            }

            if (ds.ReportingEndDate != null)
            {
                if (!String.IsNullOrEmpty(ds.ReportingEndDate.TimePeriod))
                {
                    dataset.Add(new XAttribute("reportingEndDate", ds.ReportingEndDate.TimePeriod));
                }
            }

            if (ds.ValidFromDate != null)
            {
                if (!String.IsNullOrEmpty(ds.ValidFromDate.TimePeriod))
                {
                    dataset.Add(new XAttribute("validFromDate", ds.ValidFromDate.TimePeriod));
                }
            }

            if (ds.ValidToDate != null)
            {
                if (!String.IsNullOrEmpty(ds.ValidToDate.TimePeriod))
                {
                    dataset.Add(new XAttribute("validToDate", ds.ValidToDate.TimePeriod));
                }
            }

            if (ds.PublicationYear != null)
            {
                if (!String.IsNullOrEmpty(ds.PublicationYear))
                {
                    dataset.Add(new XAttribute("publicationYear", ds.PublicationYear));
                }
            }

            if (ds.PublicationPeriod != null)
            {
                if (!String.IsNullOrEmpty(ds.PublicationPeriod.TimePeriod))
                {
                    dataset.Add(new XAttribute("publicationPeriod", ds.PublicationPeriod.TimePeriod));
                }
            }

            if (ds.Keyfamilyref != null)
            {
                dataset.Add(getKeyfamilyRef(ds.Keyfamilyref));
            }

            if(ds.Attributes.Count > 0)
            {
                XElement attribute = new XElement(Namespaces.GetNS("generic") + "Attributes");

                foreach (SDMX_Generic.ValueType att in ds.Attributes)
                {
                    attribute.Add(getValueType(att, "Value"));
                }

                dataset.Add(attribute);
            }

            //One of the Group or Series can exist more than one time
            //but not both at the same time
            if(ds.Group.Count > 0)
            {
                foreach (SDMX_Generic.GroupType group in ds.Group)
                {
                    dataset.Add(getGroup(group));
                }
            }
            else if(ds.Series.Count > 0)
            {
                foreach (SDMX_Generic.SeriesType seriestype in ds.Series)
                {
                    dataset.Add(getSeries(seriestype));
                }
            }

            if(ds.Annotations != null)
            {
                XElement annotations = ElementBuilder.GetAnnotations(ds.Annotations, Namespaces.GetNS("generic"));
                
                 dataset.Add(annotations);
            }


            return dataset;

        }

        private XElement getKeyfamilyRef(SDMX_Common.IDType keyfref)
        {
            XElement element = new XElement(Namespaces.GetNS("generic") + "KeyFamilyRef");

            if(keyfref != null)
            {
                if(keyfref.Value != null)
                    element.Value = keyfref.Value;
            }

            return element;
        }

        private XElement getGroup(SDMX_Generic.GroupType grouptype)
        {
            XElement group = new XElement(Namespaces.GetNS("generic") + "Group");

            if (grouptype.Type != null)
            {
                group.Add(new XAttribute("type", grouptype.Type));
            }

            if(grouptype.Groupkey.Count > 0)
            {
                XElement groupkey = new XElement(Namespaces.GetNS("generic") + "GroupKey");

                foreach (SDMX_Generic.ValueType valuetype in grouptype.Groupkey)
                {
                    groupkey.Add(getValueType(valuetype, "Value"));
                }

                group.Add(groupkey);
            }
              
            if(grouptype.Attributes.Count > 0)
            {
                XElement attribute = new XElement(Namespaces.GetNS("generic") + "Attributes");

                foreach (SDMX_Generic.ValueType att in grouptype.Attributes)
                {
                    attribute.Add(getValueType(att, "Value"));
                }

                group.Add(attribute);
            }

            if(grouptype.Series.Count > 0)
            {
                foreach (SDMX_Generic.SeriesType serie in grouptype.Series)
                {
                    group.Add(getSeries(serie));
                }
            }

            if(grouptype.Annotations != null)
            {
                XElement annotations = ElementBuilder.GetAnnotations(grouptype.Annotations, Namespaces.GetNS("generic"));

                group.Add(annotations);
            }

            return group;

        }

        private XElement getValueType(SDMX_Generic.ValueType valuetype, string elementName)
        {
            XElement element = new XElement(Namespaces.GetNS("generic") + elementName);

            if(valuetype.Value != null)
                element.Add(new XAttribute("value", valuetype.Value));

            if(valuetype.Concept != null)
            {
                SDMX_Common.IDType id = valuetype.Concept;
                element.Add(new XAttribute("concept", id.Value));
            }

            if(valuetype.StartTime != null)
                element.Add(new XAttribute("startTime", valuetype.StartTime));

            return element;
        }

         private XElement getSeries(SDMX_Generic.SeriesType seriestype)
        {
            XElement element = new XElement(Namespaces.GetNS("generic") + "Series");
            
            if(seriestype.Serieskey.Count > 0)
            {
                XElement serieskey = new XElement(Namespaces.GetNS("generic") + "SeriesKey");

                foreach (SDMX_Generic.ValueType sk in seriestype.Serieskey)
                {
                    serieskey.Add(getValueType(sk, "Value"));
                }

                element.Add(serieskey);
            }

            if(seriestype.Attributes.Count > 0)
            {
                XElement attribute = new XElement(Namespaces.GetNS("generic") + "Attributes");

                foreach (SDMX_Generic.ValueType at in seriestype.Attributes)
                {
                    attribute.Add(getValueType(at, "Value"));
                }

                element.Add(attribute);
            }

            if(seriestype.Obs.Count > 0)
            {
                foreach (SDMX_Generic.ObsType obstype in seriestype.Obs)
                {
                    element.Add(getObs(obstype));
                }

            }

            return element;
        }

        private XElement getObs(SDMX_Generic.ObsType obstype)
        {
            XElement element = new XElement(Namespaces.GetNS("generic") + "Obs");

            if (!String.IsNullOrEmpty(obstype.Time))
            {
                XElement time = new XElement(Namespaces.GetNS("generic") + "Time");
                time.Value = obstype.Time;
                element.Add(time);
            }
            else
            {
                throw new Exception("Time in ObsType is required.");
            }

            if(obstype.ObsValue != null)
            {
                SDMX_Generic.ObsValueType obsvalue = obstype.ObsValue;

                XElement value = new XElement(Namespaces.GetNS("generic") + "ObsValue");
                value.Add(new XAttribute("value", obsvalue.Value));

                if (!String.IsNullOrEmpty(obsvalue.StartTime))
                {
                    value.Add(new XAttribute("startTime", obsvalue.StartTime));
                }

                element.Add(value);

                if(obstype.Attributes.Count > 0)
                {
                    XElement attributes = new XElement(Namespaces.GetNS("generic") + "Attributes");

                    foreach (SDMX_Generic.ValueType valuetype in obstype.Attributes)
                    {
                        attributes.Add(getValueType(valuetype, "Value"));
                    }

                    element.Add(attributes);
                }
            }

            if(obstype.Annotations != null)
            {
                XElement annotations = ElementBuilder.GetAnnotations(obstype.Annotations, Namespaces.GetNS("generic"));

                element.Add(annotations);
            }

            return element;
        }

        

        #endregion

        #region Properties

        /// <summary>
        /// Headet for message.
        /// </summary>
        public SDMX_Message.HeaderType Header
        {
            get { return _header; }
            set { _header = value; }
        }
        
        /// <summary>
        /// Dataset containing data.
        /// </summary>
        public SDMX_Generic.DataSetType Dataset
        {
            get { return _dataset; }
            set { _dataset = value; }
        }

        #endregion

        #region Public methods

        /// <summary>
        /// Writes the content to a xml file.
        /// </summary>
        /// <param name="file">Path and name of file.</param>
        /// <param name="content">Content of a SDMX_ML file.</param>
        public void Write(string file, string content)
        {
            try
            {
                using (TextWriter writer = new StreamWriter(file))
                {
                    try
                    {
                        writer.Write(content);
                    }
                    catch (Exception ex)
                    {
                        throw new Exception("Unexpected error when wrting to file. " + ex.Message);
                    }
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Unexpected error when creating file. " + ex.Message);
            }
        }
        /// <summary>
        /// Load SDMX_ML GenericData file into GenericData object.
        /// </summary>
        /// <param name="file">Path and name of file.</param>
        /// <returns></returns>
        public static GenericData Load(string file)
        {
            GenericData genericData = null;

            if (File.Exists(file))
            {
                using (TextReader reader = new StreamReader(file))
                {
                    string fileContent = reader.ReadToEnd();

                    try
                    {
                        genericData = new GenericData(fileContent);
                    }
                    catch (Exception ex)
                    {
                        throw new Exception("Unexpected error when creating GenericData object. " + ex.Message);
                    }
                }

                return genericData;
            }
            else
            {
                throw new FileNotFoundException("File not found when trying to create GenericData object.", file);
            }
        }

        #endregion
    }
}
